package com.heaven.service.impl;

import com.heaven.constant.CommentConstants;
import com.heaven.core.dao.CommentDao;
import com.heaven.core.entity.CommentEntity;
import com.heaven.core.entity.UserEntity;
import com.heaven.core.entity.VideoEntity;
import com.heaven.core.framework.PzServiceImpl;
import com.heaven.customerServer.customerController.LoginController;
import com.heaven.customerServer.customerController.vo.comment.LoadCommentRes;
import com.heaven.customerServer.customerController.vo.comment.SendCommentReq;
import com.heaven.customerServer.customerController.vo.login.LoginRes;
import com.heaven.exception.BizCodeEnum;
import com.heaven.exception.RRException;
import com.heaven.service.CommentService;
import com.heaven.service.UserService;
import com.heaven.service.VideoService;
import com.heaven.utils.BeanUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

@Service("commentService")
@Slf4j
public class CommentServiceImpl extends PzServiceImpl<CommentDao, CommentEntity> implements CommentService {
    @Resource
    private UserService userService;
    @Resource
    private VideoService videoService;
    @Resource
    private LoginController loginController;
    @Resource
    RedissonClient redissonClient;

    @Override
    public CommentEntity addComment(SendCommentReq req, String userId) {
        if(req.getType() == CommentConstants.COMMENT_TYPE_VIDEO) {
            VideoEntity videoEntity = videoService.selectById(req.getTargetId());
            if(videoEntity == null)
                throw new RRException(BizCodeEnum.VIDEO_NOT_EXIST);
        }
        CommentEntity comment = new CommentEntity();
        BeanUtils.copyProperties(req, comment);
        comment.setUserId(userId);
        comment.setBeLikedUserIds(new HashSet<>());
        comment.setBeDislikedUserIds(new HashSet<>());

        save(comment);
        return comment;
    }

    @Override
    @Cacheable(value = "comment", key = "#root.args[0]")
    public List<LoadCommentRes> loadComment(String targetId, int type, int page, int size, String sort) {
        // 搜索一级评论
        Query query = new Query();
        query.addCriteria(Criteria.where("target_id").is(targetId)
                        .and("father_id").is("")
                        .and("type").is(type));
        List<LoadCommentRes> ans = new ArrayList<>();
        LoginRes.UserSession userSession = loginController.getUserSession();
        boolean loginStatus = userSession != null;

        if(sort.equals(CommentConstants.COMMENT_SORT_HOT)) {
            // TODO 评论热度排序

            return ans;
        } else if(sort.equals(CommentConstants.COMMENT_SORT_TIME)) {
            query.with(Sort.by(Sort.Direction.DESC, "time"));
            // 搜索一级评论
            List<CommentEntity> commentLeve1List = selectList(query, size, page);
            // 搜索二级评论
            for(CommentEntity commentLevel1 : commentLeve1List) {
                LoadCommentRes level1 = new LoadCommentRes();
                BeanUtils.copyProperties(commentLevel1, level1);

                level1.setUserInfo(getCommentUserInfo(level1.getUserId()));

                AtomicReference<RLock> rLock = new AtomicReference<>(redissonClient.getReadWriteLock(CommentConstants.LIKE_DISLIKE_COLLECT_LOCK + commentLevel1.getCommentId()).readLock());

                rLock.get().lock();
                level1.setBeLikedCount(commentLevel1.getBeLikedUserIds().size());
                level1.setBeDislikedCount(commentLevel1.getBeDislikedUserIds().size());
                level1.setChildren(new ArrayList<>());
                level1.setLiked(loginStatus && commentLevel1.getBeLikedUserIds().contains(userSession.getUserId()));
                level1.setDisliked(loginStatus && commentLevel1.getBeDislikedUserIds().contains(userSession.getUserId()));
                rLock.get().unlock();

                //该一级评论下所有的二级评论
                Query query2 = new Query();
                query2.addCriteria(Criteria.where("father_id").is(level1.getCommentId()))
                        .with(Sort.by(Sort.Direction.ASC, "time"));
                List<CommentEntity> level2List = selectList(query2);

                level2List.forEach(level2Entity -> {
                    LoadCommentRes level2 = new LoadCommentRes();
                    BeanUtils.copyProperties(level2Entity, level2);

                    level2.setUserInfo(getCommentUserInfo(level2Entity.getUserId()));
                    if(!level2.getToCommentId().equals(level2.getFatherId())) {
                        // 评论二级评论的评论
                        CommentEntity toComment = selectById(level2Entity.getToCommentId());

                        level2.setToUserInfo(getCommentUserInfo(toComment.getUserId()));
                    }
                    rLock.set(redissonClient.getReadWriteLock(CommentConstants.LIKE_DISLIKE_COLLECT_LOCK + level2.getCommentId()).readLock());
                    rLock.get().lock();
                    level2.setBeLikedCount(level2Entity.getBeLikedUserIds().size());
                    level2.setBeDislikedCount(level2Entity.getBeDislikedUserIds().size());
                    level2.setLiked(loginStatus && level2Entity.getBeLikedUserIds().contains(userSession.getUserId()));
                    level2.setDisliked(loginStatus && level2Entity.getBeDislikedUserIds().contains(userSession.getUserId()));
                    rLock.get().unlock();

                    level1.getChildren().add(level2);
                });
                ans.add(level1);
            }
            return ans;
        } else {
            throw new RRException(BizCodeEnum.ILLEGAL_COMMENT_SORT);
        }
    }

    @Override
    public LoadCommentRes.UserInfo getCommentUserInfo(String userId) {
        UserEntity user = userService.selectById(userId);
        user = userService.initUser(user);
        LoadCommentRes.UserInfo info = new LoadCommentRes.UserInfo();
        BeanUtils.copyProperties(user, info);
        return info;
    }

    @Override
    public void handleLikeOrDislike(String commentId, String userId, int type) {
        CommentEntity commentEntity = selectById(commentId);
        RLock wLock = redissonClient.getReadWriteLock(CommentConstants.LIKE_DISLIKE_COLLECT_LOCK + commentId).writeLock();
        Set<String> likeCollect = commentEntity.getBeLikedUserIds();
        Set<String> dislikeCollect = commentEntity.getBeDislikedUserIds();

        if (type == CommentConstants.COMMENT_HANDLE_LIKE) {
            // 用户点击赞键的处理逻辑
            if(likeCollect.contains(userId)) {
                // 用户已经点过赞，取消赞
                likeCollect.remove(userId);
                commentEntity.setBeLikedUserIds(likeCollect);
                updateById(commentId, commentEntity);
            } else {
                // 用户没有点过赞，点赞
                likeCollect.add(userId);
                commentEntity.setBeLikedUserIds(likeCollect);
                if(dislikeCollect.contains(userId)) {
                    // 用户已经点过踩，取消踩
                    dislikeCollect.remove(userId);
                    commentEntity.setBeDislikedUserIds(dislikeCollect);
                }
                updateById(commentId, commentEntity);
            }
        }

        if (type == CommentConstants.COMMENT_HANDLE_DISLIKE) {
            // 用户点击踩键的处理逻辑

            if(dislikeCollect.contains(userId)) {
                // 用户已经点过踩，取消踩
                dislikeCollect.remove(userId);
                commentEntity.setBeDislikedUserIds(dislikeCollect);
                updateById(commentId, commentEntity);
            } else {
                // 用户没有点过踩，踩
                dislikeCollect.add(userId);
                commentEntity.setBeDislikedUserIds(dislikeCollect);
                if(likeCollect.contains(userId)) {
                    // 用户已经点过赞，取消赞
                    likeCollect.remove(userId);
                    commentEntity.setBeLikedUserIds(likeCollect);
                }
                updateById(commentId, commentEntity);
            }
        }
        wLock.unlock();
    }
}
